#include<iostream>

#include<stdio.h>

#include<pthread.h>

#include<semaphore.h>

#include<string>

#include<vector>

#include<unistd.h>

#include<time.h>

#define Task task<int>

#define Rblock_Queue rblock_queue<int>

using namespace std;

template<class T>
class rblock_queue;

template<class T>
struct task
{
    task(const string& name, int num, Rblock_Queue* const rq): _name(name), _RQ(rq)
    {
        _name += to_string(num);
    }

    string _name;
    pthread_t _PT;
    Rblock_Queue* _RQ;
};

template<class T>
class rblock_queue
{
public:
    rblock_queue(): _qu(_cap), _head(0), _tail(0)
    {
        sem_init(&c_st, 0, 0);
        sem_init(&p_st, 0, _cap);
        pthread_mutex_init(&c_mt, nullptr);
        pthread_mutex_init(&p_mt, nullptr);
    }

    void push(const T& x)
    {
        sem_wait(&p_st);

        pthread_mutex_lock(&p_mt);
        _qu[_head++] = x;
        _head %= _cap;
        pthread_mutex_unlock(&p_mt);

        sem_post(&c_st);
    }

    T pop()
    {
        sem_wait(&c_st);

        pthread_mutex_lock(&c_mt);
        const T& ret = _qu[_tail++];
        _tail %= _cap;
        pthread_mutex_unlock(&c_mt);

        sem_post(&p_st);
        return ret;
    }

    ~rblock_queue()
    {
        sem_destroy(&c_st);
        sem_destroy(&p_st);
        pthread_mutex_destroy(&c_mt);
        pthread_mutex_destroy(&p_mt);
    }

private:
    int _cap = 5;
    vector<T> _qu;
    int _head;
    int _tail;
    sem_t c_st;
    sem_t p_st;
    pthread_mutex_t c_mt;
    pthread_mutex_t p_mt;
};

// 静态在多个类类型对象存在时不好用
// template<class T>
// pthread_mutex_t rblock_queue<T>::c_mt = PTHREAD_MUTEX_INITIALIZER;

// template<class T>
// pthread_mutex_t rblock_queue<T>::p_mt = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t m_mt = PTHREAD_MUTEX_INITIALIZER;

void* my_producer(void* arg)
{
    Task* tk = static_cast<Task*>(arg);

    while(1)
    {
        sleep(2);
        int n = rand() % 10 + 1;
        tk->_RQ->push(n);
    
        pthread_mutex_lock(&m_mt);
        cout << tk->_name << "生产了：" << n << endl;
        pthread_mutex_unlock(&m_mt);
    }

    return nullptr;
}

void* my_consumer(void* arg)
{
    Task* tk = static_cast<Task*>(arg);

    while(1)
    {
        sleep(1);
        int ret = tk->_RQ->pop();

        pthread_mutex_lock(&m_mt);
        cout << tk->_name << "消费了：" << ret << endl;
        pthread_mutex_unlock(&m_mt);
    }

    return nullptr;
}

int main()
{
    srand(time(nullptr));

    vector<Task*> arr;
    Rblock_Queue bq;

    for(int i = 0; i < 5; ++i)
    {
        Task* tk = new Task("my_producer_thread", i, &bq);
        pthread_create(&(tk->_PT), nullptr, my_producer, (void*)tk);
        arr.push_back(tk);
    }

    for(int i = 0; i < 5; ++i)
    {
        Task* tk = new Task("my_consumer_thread", i, &bq);
        pthread_create(&(tk->_PT), nullptr, my_consumer, (void*)tk);
        arr.push_back(tk);
    }

    for(auto& e : arr)
        pthread_join(e->_PT, nullptr);

    for(auto& e : arr)
        delete e;
    
    return 0;
}